"""Python class representation of a Raster Foundry Scene"""

import uuid
from requests.exceptions import HTTPError
import logging

from rf.models.base import BaseModel
from rf.models.thumbnail import Thumbnail
from rf.models.image import Image
from rf.models.footprint import Footprint

logger = logging.getLogger(__name__)


class Scene(BaseModel):

    URL_PATH = "/api/scenes/"

    def __init__(
        self,
        visibility,
        tags,
        datasource,
        sceneMetadata,
        name,
        thumbnailStatus,
        boundaryStatus,
        ingestStatus,
        metadataFiles,
        sunAzimuth=None,
        sunElevation=None,
        cloudCover=None,
        acquisitionDate=None,
        id=None,
        thumbnails=None,
        tileFootprint=None,
        dataFootprint=None,
        images=None,
        createdAt=None,
        modifiedAt=None,
        createdBy=None,
        ingestLocation=None,
        owner=None,
        sceneType="AVRO",
        metadataFields=None,
    ):
        """Create a new Scene

        Args:
            visibility (str): level of access to search for/view scene
            tags (List[str]): list of tags for scene
            datasource (str): datasource that scene belongs to
            sceneMetadata (dict): extra metadata associated with scene
            name (str): name of scene (displayed to users)
            thumbnailStatus (str): status of thumbnail creation
            boundaryStatus (str): status of creating boundaries
            ingestStatus (str): overall status of scene creation
            sunAzimuth (float): azimuth of sun when scene was created from satellite/uav
            sunElevation (float): elevation of sun when scene was created
            cloudCover (float): percent of scene covered by clouds
            acquisitionDate (datetime): date when scene was acquired
            id (str): UUID primary key for scene
            thumbnails (List[Thumbnail]): list of thumbnails associated with scene
            tileFootprint (Footprint): footprint of the tile associated with scene
            dataFootprint (Footprint): footprint of this scene's data
            images (List[Image]): list of images associated with scene
            owner (str): user that owns a scene
        """

        self.ingestLocation = ingestLocation
        self.createdBy = createdBy
        self.visibility = visibility
        self.tags = tags
        self.datasource = datasource
        self.sceneMetadata = sceneMetadata
        self.name = name
        self.thumbnailStatus = thumbnailStatus
        self.boundaryStatus = boundaryStatus
        self.ingestStatus = ingestStatus
        self.metadataFiles = metadataFiles
        self.owner = owner
        self.sceneType = sceneType

        # Optional - can be None
        self.sunAzimuth = sunAzimuth
        self.sunElevation = sunElevation
        self.cloudCover = cloudCover
        self.acquisitionDate = acquisitionDate
        self.id = id or str(uuid.uuid4())
        self.thumbnails = thumbnails
        self.tileFootprint = tileFootprint
        self.dataFootprint = dataFootprint
        self.images = images
        self.createdAt = createdAt
        self.modifiedAt = modifiedAt
        self.metadataFields = metadataFields

    def __repr__(self):
        return "<Scene: {}>".format(self.name)

    @classmethod
    def from_dict(cls, d):
        statuses = d.get("statusFields")
        filter_fields = d.get("filterFields")
        images = [Image.from_dict(image) for image in d.get("images")]
        thumbnails = [
            Thumbnail.from_dict(thumbnail) for thumbnail in d.get("thumbnails")
        ]

        tile_footprint_dict = d.get("tileFootprint")
        data_footprint_dict = d.get("dataFootprint")

        if tile_footprint_dict:
            tile_footprint = Footprint.from_dict(tile_footprint_dict)
        else:
            tile_footprint = None
        if data_footprint_dict:
            data_footprint = Footprint.from_dict(data_footprint_dict)
        else:
            data_footprint = None

        return cls(
            d.get("visibility"),
            d.get("tags"),
            d.get("datasource")["id"],
            d.get("sceneMetadata"),
            d.get("name"),
            statuses.get("thumbnailStatus"),
            statuses.get("boundaryStatus"),
            statuses.get("ingestStatus"),
            d.get("metadataFiles"),
            filter_fields.get("sunAzimuth"),
            filter_fields.get("sunElevation"),
            filter_fields.get("cloudCover"),
            filter_fields.get("acquisitionDate"),
            d.get("id"),
            thumbnails,
            tile_footprint,
            data_footprint,
            images,
            d.get("createdAt"),
            d.get("modifiedAt"),
            d.get("createdBy"),
            d.get("ingestLocation", ""),
            owner=d.get("owner"),
            sceneType=d.get("sceneType"),
            metadataFields=d.get("metadataFields"),
        )

    def to_dict(self):
        filterFields = {}
        statusFields = dict(
            thumbnailStatus=self.thumbnailStatus,
            boundaryStatus=self.boundaryStatus,
            ingestStatus=self.ingestStatus,
        )
        scene_dict = dict(
            visibility=self.visibility,
            tags=self.tags,
            datasource=self.datasource,
            sceneMetadata=self.sceneMetadata,
            filterFields=filterFields,
            name=self.name,
            statusFields=statusFields,
            metadataFiles=self.metadataFiles,
            ingestLocation=self.ingestLocation,
            owner=self.owner,
            sceneType=self.sceneType,
            metadataFields=self.metadataFields,
        )

        if self.sunAzimuth:
            filterFields["sunAzimuth"] = self.sunAzimuth
        if self.sunElevation:
            filterFields["sunElevation"] = self.sunElevation
        if self.cloudCover is not None:
            filterFields["cloudCover"] = self.cloudCover
        if self.acquisitionDate:
            filterFields["acquisitionDate"] = self.acquisitionDate
        if self.id:
            scene_dict["id"] = self.id

        if self.thumbnails:
            scene_dict["thumbnails"] = [
                thumbnail.to_dict() for thumbnail in self.thumbnails
            ]
        else:
            scene_dict["thumbnails"] = []

        if self.images:
            scene_dict["images"] = [image.to_dict() for image in self.images]
        else:
            scene_dict["images"] = []

        if self.tileFootprint:
            scene_dict["tileFootprint"] = self.tileFootprint.to_dict()
        if self.dataFootprint:
            scene_dict["dataFootprint"] = self.dataFootprint.to_dict()

        if self.createdAt:
            scene_dict["createdAt"] = self.createdAt

        if self.modifiedAt:
            scene_dict["modifiedAt"] = self.modifiedAt

        if self.createdBy:
            scene_dict["createdBy"] = self.createdBy

        return scene_dict

    def create(self):
        try:
            return super(Scene, self).create()
        except HTTPError as exc:
            if exc.response.status_code != 409:
                raise
            else:
                logger.info("Tried to create duplicate object: %s", self)
                return None

    def get_extent(self):
        """Helper method to return extent of scene"""

        assert self.tileFootprint, "Must have tile footprint to extract extent"
        coords = self.tileFootprint.multipolygon[0][0]
        longitudes = [coord[0] for coord in coords]
        latitudes = [coord[1] for coord in coords]
        return [min(longitudes), min(latitudes), max(longitudes), max(latitudes)]
